// Copyright (C) 2022 即时通讯网(52im.net) & Jack Jiang.
// The RainbowChat Project. All rights reserved.
//
// 【本产品为著作权产品，合法授权后请放心使用，禁止外传！】
// 【本次授权给：<广西木子科技有限公司>，授权编号：<NT220402151538>，代码指纹：<A.648883738.885>，技术对接人微信：<ID: Lingmuziyi>】
// 【授权寄送：<收件：李先生、地址：南宁市科园西十路11号国电智能大厦1101F、电话：17736659550、邮箱：yingshashou@vip.qq.com>】
//
// 【本系列产品在国家版权局的著作权登记信息如下】：
// 1）国家版权局登记名(简称)和权证号：RainbowChat    （证书号：软著登字第1220494号、登记号：2016SR041877）
// 2）国家版权局登记名(简称)和权证号：RainbowChat-Web（证书号：软著登字第3743440号、登记号：2019SR0322683）
// 3）国家版权局登记名(简称)和权证号：RainbowAV      （证书号：软著登字第2262004号、登记号：2017SR676720）
// 4）国家版权局登记名(简称)和权证号：MobileIMSDK-Web（证书号：软著登字第2262073号、登记号：2017SR676789）
// 5）国家版权局登记名(简称)和权证号：MobileIMSDK    （证书号：软著登字第1220581号、登记号：2016SR041964）
// * 著作权所有人：江顺/苏州网际时代信息科技有限公司
//
// 【违法或违规使用投诉和举报方式】：
// 联系邮件：jack.jiang@52im.net
// 联系微信：hellojackjiang
// 联系QQ号：413980957
// 授权说明：http://www.52im.net/thread-1115-1-1.html
// 官方社区：http://www.52im.net
package com.x52im.rainbowchat.im;

import java.util.ArrayList;
import java.util.Iterator;

import org.slf4j.Logger;

import com.eva.framework.utils.LoggerFactory;
import com.x52im.rainbowchat.common.dto.cnst.UserProtocalsType;
import com.x52im.rainbowchat.im.concurrent.CommonConcurrentExecutor;

import net.x52im.mobileimsdk.server.event.MessageQoSEventListenerS2C;
import net.x52im.mobileimsdk.server.protocal.Protocal;

/**
 * 服务端的QoS消息送达保证机制的事件监听器.实现类。
 * <p>
 * <b>当前QoS机制支持全部的C2C、C2S、S2C共3种消息交互场景下的消息送达质量保证：<</b>>
 * <ur>
 * <li>1) Client to Server(C2S)：即由某客户端主动发起，消息最终接收者是服务端，此模式下：重发由C保证、ACK应答由S发回；</li>
 * <li>2) Server to Client(S2C)：即由服务端主动发起，消息最终接收者是某客户端，此模式下：重发由S保证、ACK应答由C发回；</li>
 * <li>2) Client to Client(C2C)：即由客户端主动发起，消息最终接收者是另一客户端。此模式对于QoS机制来说，相当于C2S+S2C两程路径。</li>
 * </ul>
 * <p>
 * TCP理论上能从底层保证数据的可靠性，但应用层的代码和场景中存在网络本身和网络之外的可种不可靠性，
 * MobileIMSDK中的QoS送达保证机制，将加强TCP的可靠性，确保消息，无法从哪一个层面和维度，都会给
 * 开发者提供两种结果：要么明确被送达（即收到ACK应答包，见 {@link #messagesBeReceived(String)}）
 * 、要行明确未被送达（见 {@link #messagesLost(ArrayList)}）。从理论上，保证消息的百分百送达率。
 *
 * @author Jack Jiang
 * @see net.x52im.mobileimsdk.server.qos.QoS4SendDaemonS2C
 * @see net.x52im.mobileimsdk.server.qos.QoS4ReciveDaemonC2S
 * @see net.x52im.mobileimsdk.server.event.MessageQoSEventListenerS2C
 * @since 7.0
 */
public class MessageQoSEventListner implements MessageQoSEventListenerS2C {
    private static Logger logger = LoggerFactory.getLog();

    /**
     * 消息未送达的回调事件通知.
     *
     * @param lostMessages 由MobileIMSDK QoS算法判定出来的未送达消息列表（此列表
     *                     中的Protocal对象是原对象的clone（即原对象的深拷贝），请放心使用哦），应用层
     *                     可通过指纹特征码找到原消息并可以UI上将其标记为”发送失败“以便即时告之用户
     */
    @Override
    public void messagesLost(final ArrayList<Protocal> lostMessages) {
        logger.debug("【QoS_S2C事件[未实时送达]】收到系统的未实时送达事件通知，当前共有"
                + lostMessages.size() + "个包QoS保证机制结束，判定为【无法实时送达】！");

        if (lostMessages.size() > 0) {
            // 将处理放在独立的线程池中处理以提升处理效率，防止在大用户量时阻塞主服务
            CommonConcurrentExecutor.getInstance().execute(new Runnable() {
                @Override
                public void run() {
                    // 大数据量的情况下，iterator性能要大大优于普通的数组for循环
                    Iterator<Protocal> pit = lostMessages.iterator();
                    while (pit.hasNext()) {
                        Protocal p = pit.next();
                        if (p != null) {
//							// 目前，对于应用层来说，只有群聊消息或指令是走S2C消息路径，所以此QoS事件处理中，
//							// 只需要针对群聊，一对一消息（包括好友和陌生人聊天）走的是MobileIMSDK的客户端QoS机制
//							if(p.getTypeu() == UserProtocalsType.MT45_OF_GROUP$CHAT$MSG_SERVER$TO$B)
//							{
//								logger.debug("【DEBUG_QoS_S2C事件】未送达的是群聊消息，马上进行离线处理，fp="+p.getFp());
//								OfflineMessageManager.processOfflineMessage(p, false);
//							}

                            try {
                                // 一对一好友聊天的消息因走的是C2C消息路径，所以不需要在QoS机制中处理聊天记录了，
                                // 因为它已在 ServerEventListener.onTransferMessage4C2C()中处理，这里再做就会重复哦
                                if (p.getTypeu() == UserProtocalsType.MT03_OF_CHATTING_MESSAGE) {
                                    ChatServerLauncher.getInstance().getServerEventListener()
                                            .onTransferMessage_RealTimeSendFaild_impl(p, true);
                                } else {
                                    ChatServerLauncher.getInstance().getServerEventListener()
                                            .onTransferMessage_RealTimeSendFaild_impl(p, false);
                                }
                            } catch (Exception e) {
                                logger.warn("【QoS_S2C事件[未实时送达]】离线处理出错了，原因是：" + e.getMessage(), e);
                            }
                        }
                    }
                }
            });
        }
    }

    /**
     * 消息已被对方收到的回调事件通知.
     * <p>
     * <b>目前，判定消息被对方收到是有两种可能：</b><br>
     * 1) 对方确实是在线并且实时收到了；<br>
     * 2) 对方不在线或者服务端转发过程中出错了，由服务端进行离线存储成功后的反馈
     * （此种情况严格来讲不能算是“已被收到”，但对于应用层来说，离线存储了的消息
     * 原则上就是已送达了的消息：因为用户下次登陆时肯定能通过HTTP协议取到）。
     *
     * @param theFingerPrint 已被收到的消息的指纹特征码（唯一ID），应用层可据此ID
     *                       来找到原先已发生的消息并可在UI是将其标记为”已送达“或”已读“以便提升用户体验
     */
    @Override
    public void messagesBeReceived(String theFingerPrint) {
        if (theFingerPrint != null) {
            logger.debug("【QoS_S2C事件】收到对方已收到消息事件的通知，fp=" + theFingerPrint);
        }
    }
}
